#include "tcpclient.h"
#include "ui_tcpclient.h"
#include<QByteArray>
#include<QMessageBox>
#include<QDebug>
#include <QHostAddress>
#include"privatechat.h"

TcpClient::TcpClient(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::TcpClient)
{
    ui->setupUi(this);
    loadConfig();

    //当连接服务器成功，会产生connected信号
    connect(&m_tcpSocket,&QTcpSocket::connected,this,&TcpClient::showConnect);
    //当客户端收到服务器发来的数据时，会产生readyRead信号
    connect(&m_tcpSocket,&QTcpSocket::readyRead,this,&TcpClient::recvMsg);

    //连接服务器
    m_tcpSocket.connectToHost(QHostAddress(m_strIP),m_usPort);

}

TcpClient::~TcpClient()
{
    delete ui;
}

void TcpClient::loadConfig()
{
    QFile file(":/client.config");
    if(file.open(QIODevice::ReadOnly)){
        QByteArray baData = file.readAll();
        QString strData = baData.toStdString().c_str(); //c_str()转换成char*类型
        file.close();

        QStringList strList = strData.split("\r\n");
        m_strIP = strList.at(0);
        m_usPort = strList.at(1).toUShort();
        //qDebug()<<m_strIP<<"\n"<<m_usPort;
    }
    else
    {
        QMessageBox::critical(this,"open config","open config failed");
    }

}

TcpClient &TcpClient::getInstance()
{
    static TcpClient instance;
    return instance;

}

QTcpSocket &TcpClient::getTcpSocket()
{
    return m_tcpSocket;
}

QString TcpClient::loginName()
{
    return m_strLoginName;
}

QString TcpClient::curPath()
{
    return m_strCurPath;
}

void TcpClient::setCurPath(QString strCurParh)
{
    m_strCurPath = strCurParh;
}

void TcpClient::recvMsg()
{
    qDebug()<<"进入recvMsg函数";
    if(!OpeWidget::getInstance().getBook()->getDownloadStatus())
    {
        qDebug()<<m_tcpSocket.bytesAvailable();
        uint uiPDULen = 0;
        //先读取消息的总长度信息(4个字节），读取的总长度为sizeof(uint)
        m_tcpSocket.read((char*)&uiPDULen,sizeof(uint));
        qDebug()<<"长度 "<<uiPDULen<<"  PDU长度 "<<sizeof(PDU);

        //实际消息长度为总长度减去结构体前面几个备注信息字节
        uint uiMsgLen = uiPDULen - sizeof(PDU);
        //申请一个空间用于接收实际消息
        PDU* pdu = mkPDU(uiMsgLen);
        //读取实际消息，(char*)pdu + sizeof(uint)为存放接收数据的起始地址
        //(char*)pdu + sizeof(uint)为地址偏移，因为前面已经接收了uint个字节的数据，所以要往后挪动uint个字节
        m_tcpSocket.read((char*)pdu + sizeof(uint),uiPDULen - sizeof(uint));
        //根据消息类型做出相应处理
        qDebug()<<"pdu->uiMsgType "<<pdu->uiMsgType;
        switch (pdu->uiMsgType)
        {
        case ENUM_MSG_TYPE_REGIST_RESPOND:
        {
            if(0 == strcmp(pdu->caData,REGIST_OK))
            {
               QMessageBox::information(this,"注册",REGIST_OK);
            }
            else if(0 == strcmp(pdu->caData,REGIST_FAILED))
            {
                QMessageBox::warning(this,"注册",REGIST_FAILED);
            }
            break;
        }
        case ENUM_MSG_TYPE_LOGIN_RESPOND:
        {
            if(0 == strcmp(pdu->caData,LOGIN_OK))
            {
               m_strCurPath = QString("./home/%1").arg(m_strLoginName);
               QMessageBox::information(this,"登录",LOGIN_OK);
               OpeWidget::getInstance().show();
               this->hide();
            }
            else if(0 == strcmp(pdu->caData,LOGIN_FAILED))
            {
                QMessageBox::warning(this,"登录",LOGIN_FAILED);
            }
            break;
        }
        case ENUM_MSG_TYPE_ALL_ONLINE_RESPOND:
        {
            OpeWidget::getInstance().getFriend()->showAllOnlineUsr(pdu);
            break;
        }
        case ENUM_MSG_TYPE_SEARCH_USR_RESPOND:
        {
            if(0 == strcmp(SEARCH_USR_NO,pdu->caData))
            {
                QMessageBox::information(this,"搜索",
                             QString("%1: not exist").arg(OpeWidget::getInstance().getFriend()->m_strSearchName));
            }
            else if(0 == strcmp(SEARCH_USR_ONLINE,pdu->caData))
            {
                QMessageBox::information(this,"搜索",
                             QString("%1: online").arg(OpeWidget::getInstance().getFriend()->m_strSearchName));
            }
            else if(0 == strcmp(SEARCH_USR_OFFLINE,pdu->caData))
            {
                QMessageBox::information(this,"搜索",
                             QString("%1: offline").arg(OpeWidget::getInstance().getFriend()->m_strSearchName));
            }
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_REQUEST:
        {
            char caName[32] = {'\0'};
            strncpy(caName,pdu->caData+32,32);
            int ret = QMessageBox::information(this,"添加好友",QString("\'%1\' want to add you as friend").arg(caName)
                                     ,QMessageBox::Yes,QMessageBox::No);
            PDU *respdu = mkPDU(0);
            memcpy(respdu->caData,pdu->caData,32);
            if(QMessageBox::Yes == ret)
            {
                respdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_AGGREE;
            }
            else
            {
                respdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_REFUSE;
            }
            m_tcpSocket.write((char*)respdu,respdu->uiPDULen);
            free(respdu);
            respdu = NULL;
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_RESPOND:
        {
            QMessageBox::information(this,"添加好友",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_FLUSH_FRIEND_RESPOND:
        {
            OpeWidget::getInstance().getFriend()->updateFriendList(pdu);
            break;
        }
        case ENUM_MSG_TYPE_DELETE_FRIEND_REQUEST:
        {
            char caName[32] = {'\0'};
            memcpy(caName,pdu->caData,32);
            QMessageBox::information(this,"删除好友",QString("%1 删除你作为TA的好友！").arg(caName));
            break;
        }
        case ENUM_MSG_TYPE_DELETE_FRIEND_RESPOND:
        {
            QMessageBox::information(this,"删除好友","删除好友成功！");
            break;
        }
        case ENUM_MSG_TYPE_PRIVATE_CHAT_REQUEST:
        {
            if(PrivateChat::getInstance().isHidden())
            {
                PrivateChat::getInstance().show();
            }
            char caSendName[32] = {'\0'};
            memcpy(caSendName,pdu->caData,32);
            QString strSendName = caSendName;
            PrivateChat::getInstance().setChatName(strSendName);
            PrivateChat::getInstance().updateMsg(pdu);

            break;
        }
        case ENUM_MSG_TYPE_GROUP_CHAT_REQUEST:
        {
            OpeWidget::getInstance().getFriend()->updateGroupMsg(pdu);
            break;
        }
        case ENUM_MSG_TYPE_CREATE_DIR_RESPOND:
        {
            QMessageBox::information(this,"创建文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_FLUSH_FILE_RESPOND:
        {

            OpeWidget::getInstance().getBook()->updateFileList(pdu);
            //双击的是一个文件夹，之后会进入该文件的下一级目录，更新新的文件路径
            QString strEnterDir = OpeWidget::getInstance().getBook()->enterdir();//获得当前双击的文件的名字
            if(!strEnterDir.isEmpty())
            {
                //保存当前所在文件的路径
                //如果是点击返回按钮执行到此处，则strEnterDir变量为空，因为在调用flushFile函数之前清空了该变量
                m_strCurPath = m_strCurPath + "/" + strEnterDir;
            }
            break;
        }
        case ENUM_MSG_TYPE_DEL_DIR_RESPOND:
        {
            QMessageBox::information(this,"删除文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_RENAME_FILE_RESPOND:
        {
            QMessageBox::information(this,"重命名文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_ENTER_DIR_RESPOND:
        {
            //客户端双击的是一个文件，而不是一个文件夹，因为是一个文本文件，该文件下不存在子文件，所以将用
            //于保存双击后的文件名字的变量清空
            //OpeWidget::getInstance().getBook()->clearEnterDir();
            QMessageBox::information(this,"进入文件夹",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_UPLOAD_FILE_RESPOND:
        {
            QMessageBox::information(this,"上传文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_DEL_FILE_RESPOND:
        {
            QMessageBox::information(this,"删除文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_DOWNLOAD_FILE_RESPOND:
        {
            char caFileName[32] = {'\0'};
            sscanf(pdu->caData,"%s %lld",caFileName,&(OpeWidget::getInstance().getBook()->m_iTotal));
            if(strlen(caFileName) >0 &&
                    OpeWidget::getInstance().getBook()->m_iTotal > 0)
            {
                OpeWidget::getInstance().getBook()->setDownloadStatus(true);
                m_file.setFileName(OpeWidget::getInstance().getBook()->getSaveFilePath());
//                qDebug()<<"setDownloadStatus():"<<OpeWidget::getInstance().getBook()->getDownloadStatus();
//                qDebug()<<"getSaveFilePath():"<<OpeWidget::getInstance().getBook()->getSaveFilePath();

                //一个感叹号没写，改一下午的Bug!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                //弹窗会终止程序接收数据！！！！！！！！！！！！！！
                if(!m_file.open(QIODevice::WriteOnly))
                {
                    QMessageBox::warning(this,"下载文件","获得保存的文件路径失败");
                }
             }
            break;
        }
        default:
            break;
        }
        free(pdu);
        pdu = NULL;
    }
    else
    {
        QByteArray buffer = m_tcpSocket.readAll();
        qDebug()<<"已接收的buffer:"<<buffer.size();
        m_file.write(buffer);
        Book *pBook = OpeWidget::getInstance().getBook();
        pBook->m_iRecved += buffer.size();
        if(pBook->m_iTotal == pBook->m_iRecved)
        {
            m_file.close();
            pBook->m_iTotal = 0;
            pBook->m_iRecved = 0;
            pBook->setDownloadStatus(false);
        }
        else if(pBook->m_iTotal < pBook->m_iRecved)
        {
            m_file.close();
            pBook->m_iTotal = 0;
            pBook->m_iRecved = 0;
            pBook->setDownloadStatus(false);
            QMessageBox::critical(this,"下载文件","下载失败！");
        }
    }
}

void TcpClient::showConnect()
{
    QMessageBox::information(this,"连接服务器","连接服务器成功！");

}

#if 0
void TcpClient::on_send_pb_clicked()
{
    QString strMsg = ui->lineEdit->text();
    if(!strMsg.isEmpty()){
        PDU* pdu = mkPDU(strMsg.size());
        pdu->uiMsgType = 8888;  //消息类型
        //.c_str()获取数据的首地址，将要发送的数据拷贝到新申请的空间中
        memcpy(pdu->caMsg,strMsg.toStdString().c_str(),strMsg.size());
        m_tcpSocket.write((char*)pdu,pdu->uiPDULen);//uiPDULen是发送消息的长度
        free(pdu);
        pdu = NULL;
    }
    else{
        QMessageBox::information(this,"信息发送","发送信息不能为空");
    }
}
#endif

void TcpClient::on_login_pb_clicked()
{
    QString strName = ui->name_le->text();
    QString strPwd = ui->pwd_le->text();
    if(!strName.isEmpty() && !strPwd.isEmpty())
    {
        m_strLoginName = strName;
        PDU *pdu = mkPDU(0); // 此时不发送信息，所以参数值为0
        pdu->uiMsgType = ENUM_MSG_TYPE_LOGIN_REQUEST;
        //从strName中拷贝32个字节到pdu->caData中，caData的前32个字节存放用户名，
        //后32个字节存放密码
        strncpy(pdu->caData,strName.toStdString().c_str(),32);
        strncpy(pdu->caData+32,strPwd.toStdString().c_str(),32);
        m_tcpSocket.write((char*)pdu,pdu->uiPDULen);
        free(pdu);
        pdu = NULL;

    }
    else {
        QMessageBox::critical(this,"登录","登录失败:用户名或密码为空！");
    }
}

void TcpClient::on_regist_pb_clicked()
{
    QString strName = ui->name_le->text();
    QString strPwd = ui->pwd_le->text();
    if(!strName.isEmpty() && !strPwd.isEmpty())
    {
        PDU *pdu = mkPDU(0); // 此时不发送信息，所以参数值为0
        pdu->uiMsgType = ENUM_MSG_TYPE_REGIST_REQUEST;
        //从strName中拷贝32个字节到pdu->caData中，caData的前32个字节存放用户名，
        //后32个字节存放密码
        strncpy(pdu->caData,strName.toStdString().c_str(),32);
        strncpy(pdu->caData+32,strPwd.toStdString().c_str(),32);
        m_tcpSocket.write((char*)pdu,pdu->uiPDULen);
        free(pdu);
        pdu = NULL;

    }
    else {
        QMessageBox::critical(this,"注册","注册失败:用户名或密码为空！");
    }

}

void TcpClient::on_cancel_pb_clicked()
{

}
